#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
#include <math.h>

//#include <log4c/log.h>
#include <server/invokeproxy.h>
#include <cJSON/cJSON.h>
#include <server/transfercall.h>
#include <server/jsonoperation.h>
#include <server/broadcast.h>

#define INVOKE_SHARED "/etc/server/invoke_shared.conf"
#define RET_SUCCESS 0
#define RET_ERROR 1

static method_st *s_entry_table[26][26];
void invoke_init(void) __attribute__((constructor));
void invoke_fini(void) __attribute__((destructor));

/**
 * 描述：注册RPC调用函数，将业务模块中的函数节点添加到二维数组中。
 *
 * 入参：[method_st]	[IN]	[node]:远程调用函数注册节点地址。
 * 返回值：无
 *
 * 作者：王学飞
 * 日期：2016-1-5
 *
 * **/
void register_invoke_entry(method_st *node)
{
	struct method **entry;
	
	if(strlen(node->name) < 2)
		return ;
	entry = &s_entry_table[node->name[0]-'a'][node->name[1]-'a'];
	//LOG_DEBUG("function name is %s",node->name);
	node->next = *entry;
	*entry = node;
	return ;
}
/**
 * 描述：根据函数名称前两个字符在调用表中查找调用函数，并调用。
 *
 * 入参：[char *]	[IN]	[name]:远程调用函数名称
 *		 [cJSON *]	[IN]	[cj_arg]:远程调用参数
 *		 [cJSON *]	[OUT]	[cj_ret]:远程调用返回值
 * 返回值：[int]	[正确]：0	［错误］：1
 *
 * 作者：王学飞
 * 日期：2016-1-4
 *
 * **/
int inner_call(char *name, struct cJSON *cj_arg, struct cJSON *cj_ret)
{
	struct method *entry;
	struct cJSON *cj_val;	
	if(strlen(name) < 2){
		//LOG_ERROR("func error [%s]!",name);
		cJSON_AddNumberToObject(cj_ret, "ErrorCode", RET_ERROR);
		cJSON_AddStringToObject(cj_ret, "RetMessage", "func error!!!");
		return RET_ERROR;
	}
	
	entry = s_entry_table[name[0]-'a'][name[1]-'a'];
	if(!entry){
		//LOG_ERROR("func %s not found!",name);
		cJSON_AddNumberToObject(cj_ret, "ErrorCode", RET_ERROR);
		cJSON_AddStringToObject(cj_ret, "RetMessage", "func name not found!\n");
		return RET_ERROR;
	}

	while(strcmp(entry->name, name)){
		if(entry->next)
			entry = entry->next;
		else{
			//LOG_ERROR("func name not found!");
			cJSON_AddNumberToObject(cj_ret, "ErrorCode", RET_ERROR);
			cJSON_AddStringToObject(cj_ret, "RetMessage", "func name not found!\n");
			return RET_ERROR;
		}
	}

	cj_val = entry->buiness_method(cj_arg);
	if(!cj_val){
		cJSON_AddNumberToObject(cj_ret, "ErrorCode", RET_ERROR);
		cJSON_AddStringToObject(cj_ret, "RetMessage", "func inner error!!");
		return RET_ERROR;
	}

	cJSON_AddItemToObject(cj_ret, "ReturnValue", cj_val);
	cJSON_AddNumberToObject(cj_ret, "ErrorCode", RET_SUCCESS);
	return RET_SUCCESS;
}
/**
 * 描述：远程RPC入口函数，负责验证与转发，供transfer模块调用
 *
 * 入参：[char *]			[IN]	[args]:客户端传递过来的RPC参数。
 * 		 [file_ops_st *]	[IN]	[obj]:epoll监听对象，存放描述分IP地址等信息
 * 返回值:[char *] :返回调用后的结果。
 *
 * 作者：王学飞
 * 日期：2016-1-6
 *
 * **/
char *invoke(char *args)
{
	struct cJSON *cj, *cj_ret, *cj_arg;
	char *str_ret;
	int len_ret;
	int ret;
	char *name;
	//LOG_DEBUG("invoke============");
	cj_ret = cJSON_CreateObject();
	if(!cj_ret){
		//LOG_ERROR("create cJSON error!");
		str_ret = "";
		goto null_out;
	}

	cj = cJSON_Parse(args);
	if(!cj){
		//LOG_ERROR( "Error before: [%s]" , cJSON_GetErrorPtr());
		cJSON_AddNumberToObject(cj_ret, "ErrorCode", RET_ERROR);
		cJSON_AddStringToObject(cj_ret, "RetMessage", cJSON_GetErrorPtr());
		goto out;
	}

	name = cJSON_GetObjectItem(cj, "remoteFunc")->valuestring;
	if(!name){
		//LOG_ERROR( "Error before: [%s]" , cJSON_GetErrorPtr());
		cJSON_AddNumberToObject(cj_ret, "ErrorCode", RET_ERROR);
		cJSON_AddStringToObject(cj_ret, "RetMessage", cJSON_GetErrorPtr());
		goto out;
	}
	
	cj_arg = cJSON_GetObjectItem(cj, "remoteArgs");
	if(!cj_arg){
		cJSON_AddNumberToObject(cj_ret,"ErrorCode", RET_ERROR);
		cJSON_AddStringToObject(cj_ret, "RetMessage", cJSON_GetErrorPtr());
	}

	//cJSON_AddNumberToObject(cj_arg, "SockFd", ((file_ops_st *)obj)->fd);
	//cJSON_AddStringToObject(cj_arg, "Addr", ((file_ops_st *)obj)->addr);
	
	inner_call(name, cj_arg, cj_ret);

	cJSON_Delete(cj);
out:
	str_ret = cJSON_Print(cj_ret);
	cJSON_Delete(cj_ret);
null_out:
	return str_ret;
}

/**
 * 描述：解析配置文件，获得需要加载的动态库名称。
 *
 * 入参：[cJSON*]	[IN]	[cj]:解析配置文件得到的json对象。
 *		 [int*]		[OUT]	[count]:需要加载的动态库个数。
 * 返回值：[char**]	[错误]:NULL	[正确]:动态库名列表。
 *
 * 作者：王学飞
 * 日期：2016-1-7
 *
 *
 * **/
static char **get_libfile_names(cJSON *cj, int *count)
{
	struct cJSON *json_arr, *json_item ;
	int i;
	char **ret;
	json_arr = cJSON_GetObjectItem(cj, "so");
	if(!json_arr){
		//LOG_ERROR("get json arr error!!!");
		return NULL;
	}

	*count = cJSON_GetArraySize(json_arr);

	ret = (char **)malloc(sizeof(char*)*(*count));
	if(!ret){
		//LOG_ERROR("malloc error!!!!");
		return NULL;
	}
	
	bzero(ret, sizeof(char *)*(*count));

	for(i = 0; i < *count; i++){
		json_item = cJSON_GetArrayItem(json_arr, i);
		ret[i] = (char *)malloc(strlen(json_item->valuestring));
		if(!ret[i]){
			//LOG_ERROR("malloc error!!!!");
			goto out;
		}
		strcpy(ret[i], json_item->valuestring);
	}

	return ret;
out_item:
	for(i = 0; ; i++){
		if(ret[i]){
			free(ret[i]);
		}
	}

out:
	free(ret);
	return NULL;
}
/**
 * 描述：释放动态库名称申请的内存。
 * 入参：[char**]	[IN]	[lib_names]:存放动态库名称的列表。
 * 		 [int]		[IN]	[count]:动态库数量。
 *
 * **/
void destory_lib_names(char **lib_names,int count)
{
	int i;
	
	i = 0;

	if(!lib_names){
		return ;
	}

	while(i < count){
		//LOG_DEBUG("free %s",lib_names[i]);
		free(lib_names[i]);
		//LOG_DEBUG("free",lib_names[i]);
		i++;
	}

	//LOG_DEBUG("1");
	free(lib_names);
	//LOG_DEBUG("2");
}

void deal_with_handle(void *handle)
{
	method_st *(*get_object_method)(void *);
	int (*get_object_method_num)(void);
	method_st *method;
	int method_num;
	int i;

	i = 0;

	get_object_method = dlsym(handle, "get_object_method");
	if(!get_object_method){
		//LOG_ERROR("can't find object!");
		return;
	}

	get_object_method_num = dlsym(handle, "get_object_method_num");
	if(!get_object_method_num){
		//LOG_ERROR("can't find object num!");
		return;
	}
	
	method = get_object_method(inner_call);
	if(!method){
		//LOG_ERROR("can't get object!!");
		return;
	}
	method_num = get_object_method_num();
	while(i < method_num){
		register_invoke_entry(method++);
		i++;
	}
}

void init_lib_files(char **lib_name, int count)
{
	void *handle;
	int i;

	i = 0;

	while(i < count){
		handle = dlopen(lib_name[i],RTLD_NOW|RTLD_GLOBAL);
		if(!handle){
			//LOG_ERROR("dlopen %s error %s",lib_name[i],dlerror());
			break;
		}
		deal_with_handle(handle);
		bc_deal_with_handle(handle);
		i++;
	}
}

void invoke_init(void)
{
	struct cJSON *cj;
	int count;
	char **lib_names;

	printf("file:%s,line:%d,func:%s\n",__FILE__,__LINE__,__func__); 
	cj = load_json_file(INVOKE_SHARED);
	if(!cj){
		//LOG_ERROR("load json file error!!\n");
		return;
	}

	lib_names = get_libfile_names(cj, &count);
	if(!lib_names){
		return ;
	}
	
	init_lib_files(lib_names,count);
	//LOG_DEBUG("1");
}

void invoke_fini(void)
{
	;
}

